require "log"
require "http"
require "aLiOutMsg"
require "config"
require "tool"

module(..., package.seeall)

-- GWR_version：软件版本号

local gwVersion = _G.PROJECT .. _G.VERSION .. "_" ..
                      tool.Split(rtos.get_version(), '_')[2]
local gName
local fileSize = 0
local processed = 0
local flow_MD5
local lastStep

-- 升级文件下载完成，OTA回调函数，调用系统接口启动更新
local function otaCb(result, filePath, md5, size)
    log.info("aLiYunOta.otaCb", result, filePath, size,
             (type(gName) == "string") and io.fileSize(filePath) or "function")
    -- 校验MD5
    if result then
        if type(gName) == "string" then
            local calMD5 = crypto.md5(filePath, "file")
            result = (string.upper(calMD5) == string.upper(md5))
            log.info("aLiYunOta.otaCb cmp md5", result, calMD5, md5)
        else
            local calMD5 = flow_MD5:hexdigest()
            result = (string.upper(calMD5) == string.upper(md5))
            log.info("aLiYunOta.otaCb cmp md5 NOTSTRING", result, calMD5, md5)
        end
    end

    rtos.fota_end()
    if not result then
        rtos.fota_start()
        rtos.fota_end()
    end

    if result then sys.restart("ALIYUN_OTA") end
end

local function saveUpdata(pdata, binlen, statusCode)
    log.info("saveUpdata", binlen, statusCode)
    if statusCode == "206" and pdata and binlen then
        if rtos.fota_process(pdata, binlen) ~= 0 then
            -- 返回-94表示没有进行初始化，需要调用rtos.fota_start()进行更新初始化
            log.info("updata.fota_process", "fail!!",
                     rtos.fota_process(pdata, binlen))
            return
        else
            flow_MD5:update(pdata)
            -- 打印此升级包的长度跟总包长度
            processed = processed + pdata:len()
            log.info("updata.fota_process", processed, binlen)
        end
    end
end

-- 上报版本号至阿里云
function versionUpload()
    log.info("ALI_YUN version upload:", gwVersion)
    local re = {}
    re["id"] = tostring(tool.miscTime())
    re["params"] = {}
    re["params"]["version"] = gwVersion
    re["params"]["module"] = "default"
    aLiOutMsg.aLiInstertMsg("/ota/device/inform/" .. config.ALI_PRODUCTKEY ..
                                "/" .. "GWRD_" .. misc.getImei(), re)
end

-- 向阿里云更新下载进度
local function upgradeStepRpt(step, desc)
    log.info("ALI_YUN UPGRADE Download ing", step, desc)

    if aLiIotda.isReady() then
        local re = {}
        re["id"] = tostring(tool.miscTime())
        re["params"] = {}
        re["params"]["step"] = tostring(step)
        re["params"]["desc"] = tostring(desc)
        re["params"]["module"] = "default"

        if step <= 0 or step == 100 then sys.timerStop(getPercent) end
        lastStep = step
        aLiOutMsg.aLiInstertMsg(
            "/ota/device/progress/" .. config.ALI_PRODUCTKEY .. "/" .. "GWRD_" ..
                misc.getImei(), re)
    end
end

-- https下载回调函数
local function downloadCbFnc(result, prompt, head, filePath)
    log.info("aLiYunOta.downloadCbFnc", result, prompt, filePath)
    sys.publish("ALIYUN_OTA_DOWNLOAD_IND", result)
end

function getPercent()
    local step
    if type(gName) == "string" then
        step = io.fileSize(gName) * 100 / fileSize
    else
        step = processed * 100 / fileSize
    end
    log.info("aLiYunOta.getPercent", step)
    if step ~= 0 and step ~= lastStep then upgradeStepRpt(step) end
    sys.timerStart(getPercent, 5000)
end

-- 根据阿里云下发的url，下载更新固件
local function downloadTask(url, size, md5, ver)
    log.info("ALI_YUN UPGRADE Download begin", url, size, md5)

    local rangeBegin, retryCnt = 0, 0
    fileSize = size

    sys.timerStart(getPercent, 5000)

    while true do
        if not gName then gName = saveUpdata end

        http.request("GET", url, nil,
                     {["Range"] = "bytes=" .. rangeBegin .. "-"}, "", 60000,
                     downloadCbFnc, gName)
        local _, result = sys.waitUntil("ALIYUN_OTA_DOWNLOAD_IND")

        if result then
            upgradeStepRpt(100, 0)
            sys.timerStart(otaCb, 5000, true, gName, md5, size)
            break
        else
            retryCnt = retryCnt + 1
            if retryCnt >= 30 then
                upgradeStepRpt(-2, "timeout")
                otaCb(false, gName)
                break
            end
        end
        if type(gName) == "string" then
            rangeBegin = io.fileSize(gName)
        else
            rangeBegin = processed
        end
    end
end

function upgrade(payload)
    local jsonData, result = json.decode(payload)
    log.info("ALI_YUN UPGRADE RECEIVE", result, payload)

    if rtos.fota_start() ~= 0 then
        log.info("OTA ERROR", "fota_start fail")
        versionUpload()
        return
    end

    if result and jsonData.data and jsonData.data.url then
        flow_MD5 = crypto.flow_md5()
        sys.publish("UPGRADE", jsonData.data.version)
        sys.taskInit(downloadTask, jsonData.data.url, jsonData.data.size,
                     jsonData.data.md5, jsonData.data.version)
    end
end
